﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace Magic.Core;

public static class JWTAuthorizationServiceCollectionExtensions
{
    public static IServiceCollection AddJwt(this IServiceCollection services)
    {
        // 配置验证
        ConfigureJWTOptions(services);

        var jwtSettings = services.BuildServiceProvider().GetService<IOptions<JWTSettingsOptions>>().Value;

        ///如果整个服务只需要鉴权逻辑是一样的，那么用这个就行了
        //services.AddScoped<IAuthorizationHandler, AuthorizationHandler>();
        //services.AddAuthorization();

        //注册第一个鉴权策略
        services.AddScoped<IAuthorizationHandler, MagicAuthorizationHandler>();
        //注册第二个鉴权策略
        services.AddScoped<IAuthorizationHandler, MagicTestAuthorizationHandler>();
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = CreateTokenValidationParameters(jwtSettings);
                });
        services.AddAuthorization(options =>
        {
            options.AddPolicy("magic", policy => policy.Requirements.Add(new MagicAuthorizationRequirement()));
            options.AddPolicy("magicTest", policy => policy.Requirements.Add(new MagicTestAuthorizationRequirement()));
        });
        services.AddScoped<IJWTBuilder, JWTBuilder>();
        return services;
    }

    /// <summary>
    /// 生成Token验证参数
    /// </summary>
    /// <param name="jwtSettings"></param>
    /// <returns></returns>
    private static TokenValidationParameters CreateTokenValidationParameters(JWTSettingsOptions jwtSettings)
    {
        return new TokenValidationParameters
        {
            // 验证签发方密钥
            ValidateIssuerSigningKey = jwtSettings.ValidateIssuerSigningKey.Value,
            // 签发方密钥
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.IssuerSigningKey)),
            // 验证签发方
            ValidateIssuer = jwtSettings.ValidateIssuer.Value,
            // 设置签发方
            ValidIssuer = jwtSettings.ValidIssuer,
            // 验证签收方
            ValidateAudience = jwtSettings.ValidateAudience.Value,
            // 设置接收方
            ValidAudience = jwtSettings.ValidAudience,
            // 验证生存期
            ValidateLifetime = jwtSettings.ValidateLifetime.Value,
            // 过期时间容错值
            ClockSkew = TimeSpan.FromSeconds(jwtSettings.ClockSkew.Value),
        };
    }

    private static void ConfigureJWTOptions(IServiceCollection services)
    {
        // 配置验证
        services.AddOptions<JWTSettingsOptions>()
                .BindConfiguration("JWTSettings")
                .ValidateDataAnnotations()
                .PostConfigure(options =>
                {
                    _ = SetDefaultJwtSettings(options);
                });
    }

    /// <summary>
    /// 设置默认 Jwt 配置
    /// </summary>
    /// <param name="options"></param>
    /// <returns></returns>
    private static JWTSettingsOptions SetDefaultJwtSettings(JWTSettingsOptions options)
    {
        options.ValidateIssuerSigningKey ??= true;
        if (options.ValidateIssuerSigningKey == true)
        {
            options.IssuerSigningKey ??= "U2FsdGVkX1+6H3D8Q//yQMhInzTdRZI9DbUGetbyaag=";
        }
        options.ValidateIssuer ??= true;
        if (options.ValidateIssuer == true)
        {
            options.ValidIssuer ??= "magic";
        }
        options.ValidateAudience ??= true;
        if (options.ValidateAudience == true)
        {
            options.ValidAudience ??= "powerby magic";
        }
        options.ValidateLifetime ??= true;
        if (options.ValidateLifetime == true)
        {
            options.ClockSkew ??= 10;
        }
        options.ExpiredTime ??= 20;
        options.Algorithm ??= SecurityAlgorithms.HmacSha256;

        return options;
    }


}
